﻿using Engine;
using Engine.Audio;
using Engine.Graphics;
using Engine.Media;
using Game;
using GameEntitySystem;
using System;
using System.Collections.Generic;

namespace Game
{
    /// <summary>
    /// 复制方块管理
    /// </summary>
	public class CopyBlockManager
    {
        public class CopyBlockData
        {
            public int Value;
            public int Data;
            public int Id;
            public string ExtraData;
            public object DirectData;
        }

        public string WorldDirectoryName;

        public bool HandleFurniture;

        public bool HandleAir;

        public bool HandleExtraData;

        public SubsystemCommandDef SubsystemCommandDef;

        public WithdrawBlockManager WBManager;

        public CubeArea CubeArea;

        public Point3 CopyOrigin;

        public Dictionary<Point3, CopyBlockData> CopyBlockDatas = new Dictionary<Point3, CopyBlockData>();

        public CopyBlockManager(SubsystemCommandDef subsystemCommandDef, WithdrawBlockManager wbManager, Point3 point1, Point3 point2, bool handleFurniture = false, bool handleAir = false, bool handleExtraData = false)
        {
            SubsystemCommandDef = subsystemCommandDef;
            WBManager = wbManager;
            HandleFurniture = handleFurniture;
            HandleAir = handleAir;
            HandleExtraData = handleExtraData;
            WorldDirectoryName = GameManager.m_worldInfo.DirectoryName;
            CubeArea = new CubeArea(point1, point2);
            CubeArea.Ergodic(delegate
            {
                int value = SubsystemCommandDef.m_subsystemTerrain.Terrain.GetCellValue(CubeArea.Current.X, CubeArea.Current.Y, CubeArea.Current.Z);
                CopyBlockData copyData = new CopyBlockData();
                copyData.Value = value;
                copyData.Data = Terrain.ExtractData(value);
                copyData.Id = Terrain.ExtractContents(value);
                if ((!HandleAir && copyData.Id != 0) || HandleAir)
                {
                    GetCopyExtraData(copyData, CubeArea.Current);
                    CopyBlockDatas[CubeArea.Current] = copyData;
                }
                return false;
            });
        }

        public void ClearBlockArea(bool applyChangeCell = false)
        {
            foreach (var p in CopyBlockDatas.Keys)
            {
                if (!SubsystemCommandDef.m_subsystemTerrain.Terrain.IsCellValid(p.X, p.Y, p.Z)) return;
                int oldId = CopyBlockDatas[p].Id;
                if (WithdrawBlockManager.WithdrawMode && WBManager != null)
                {
                    WBManager.SetCurrentCell(p.X, p.Y, p.Z, CopyBlockDatas[p].Value, 0);
                }
                if (oldId == 27 || oldId == 45 || oldId == 64 || oldId == 216)
                {
                    ComponentBlockEntity blockEntity = SubsystemCommandDef.m_subsystemBlockEntities.GetBlockEntity(p.X, p.Y, p.Z);
                    if (blockEntity != null)
                    {
                        blockEntity.Entity.FindComponent<ComponentInventoryBase>().m_slots.Clear();
                    }
                    SubsystemCommandDef.m_subsystemTerrain.ChangeCell(p.X, p.Y, p.Z, 0);
                }
                else if (applyChangeCell)
                {
                    SubsystemCommandDef.m_subsystemTerrain.ChangeCell(p.X, p.Y, p.Z, 0);
                }
                else
                {
                    SubsystemCommandDef.m_subsystemTerrain.Terrain.SetCellValueFast(p.X, p.Y, p.Z, 0);
                }
            }
        }

        public void CopyFromCache(Point3 placePoint)
        {
            if (HandleFurniture && GameManager.m_worldInfo.DirectoryName != WorldDirectoryName)
            {
                SubsystemFurnitureBlockBehavior furnitureBlockBehavior = SubsystemCommandDef.Project.FindSubsystem<SubsystemFurnitureBlockBehavior>();
                int setIndex = 1;
                bool setNameExist;
                string setName;
                do
                {
                    setNameExist = false;
                    setName = "CommandSet" + setIndex;
                    foreach (FurnitureSet set in furnitureBlockBehavior.FurnitureSets)
                    {
                        if (set.Name == setName)
                        {
                            setNameExist = true;
                            break;
                        }
                    }
                    setIndex++;
                }
                while (setNameExist);
                int max = -1;
                for (int i = 0; i < furnitureBlockBehavior.m_furnitureDesigns.Length; i++)
                {
                    if (furnitureBlockBehavior.m_furnitureDesigns[i] != null) max = i;
                }
                List<FurnitureDesign> sortFurnitures = SortFurniture();
                if (sortFurnitures.Count > 0)
                {
                    FurnitureSet furnitureSet = furnitureBlockBehavior.NewFurnitureSet(setName, string.Empty);
                    foreach (var furniture in sortFurnitures)
                    {
                        if (furniture != null)
                        {
                            FurnitureDesign furniture2 = furniture.Clone();
                            furniture2.Index = furniture.Index + max;
                            furnitureBlockBehavior.m_furnitureDesigns[furniture2.Index] = furniture2;
                            furnitureBlockBehavior.AddToFurnitureSet(furniture2, furnitureSet);
                        }
                    }
                }
                foreach (var p in CopyBlockDatas.Keys)
                {
                    if (CopyBlockDatas[p].Id == 227 && CopyBlockDatas[p].DirectData != null)
                    {
                        FurnitureDesign furniture = (FurnitureDesign)CopyBlockDatas[p].DirectData;
                        furniture.Index = furniture.Index + max;
                        CopyBlockDatas[p].Value = Terrain.MakeBlockValue(227, 0, FurnitureBlock.SetDesignIndex(CopyBlockDatas[p].Data, furniture.Index, furniture.ShadowStrengthFactor, furniture.IsLightEmitter));
                    }
                }
            }
            foreach (var p in CopyBlockDatas.Keys)
            {
                Point3 point = placePoint - CopyOrigin + p;
                if (CopyBlockDatas[p].Id != 0)
                {
                    ChangeBlockValue(point, CopyBlockDatas[p]);
                }
            }
        }

        public void DirectCopy(Point3 placePoint, bool applyAir)
        {
            foreach (var p in CopyBlockDatas.Keys)
            {
                Point3 point = placePoint - CopyOrigin + p;
                if (!applyAir)
                {
                    if (CopyBlockDatas[p].Id != 0)
                    {
                        ChangeBlockValue(point, CopyBlockDatas[p]);
                    }
                }
                else
                {
                    ChangeBlockValue(point, CopyBlockDatas[p]);
                }
            }
        }

        public void MirrorCopy(Point3 planePoint, string plane, bool laminate)
        {
            foreach (var p in CopyBlockDatas.Keys)
            {
                if (CopyBlockDatas[p].Id != 0)
                {
                    SetMirrorValue(CopyBlockDatas[p], plane);
                    Point3 point = GetMirrorPoint(p, planePoint, plane, laminate);
                    ChangeBlockValue(point, CopyBlockDatas[p]);
                }
            }
        }

        public void RotateCopy(Point3 axisPoint, string axis, string angle, bool applyChangeCell = false)
        {
            foreach (var p in CopyBlockDatas.Keys)
            {
                if (CopyBlockDatas[p].Id != 0)
                {
                    SetRotateValue(CopyBlockDatas[p], axis, angle);
                    Point3 point = GetRotatePoint(p, axisPoint, axis, angle);
                    ChangeBlockValue(point, CopyBlockDatas[p], applyChangeCell);
                }
            }
        }

        public void ChangeBlockValue(Point3 point, CopyBlockData copyData, bool applyChangeCell = false)
        {
            if (!SubsystemCommandDef.m_subsystemTerrain.Terrain.IsCellValid(point.X, point.Y, point.Z)) return;
            int oldValue = SubsystemCommandDef.m_subsystemTerrain.Terrain.GetCellValueFast(point.X, point.Y, point.Z);
            int oldId = Terrain.ExtractContents(oldValue);
            if (WithdrawBlockManager.WithdrawMode && WBManager != null)
            {
                WBManager.SetCurrentCell(point.X, point.Y, point.Z, oldValue, copyData.Value);
            }
            if (oldId == 27 || oldId == 45 || oldId == 64 || oldId == 216)
            {
                SubsystemCommandDef.m_subsystemTerrain.ChangeCell(point.X, point.Y, point.Z, 0);
            }
            if (copyData.Id == 27 || copyData.Id == 45 || copyData.Id == 64 || copyData.Id == 216)
            {
                SubsystemCommandDef.m_subsystemTerrain.ChangeCell(point.X, point.Y, point.Z, copyData.Value);
                ComponentBlockEntity blockEntity = SubsystemCommandDef.m_subsystemBlockEntities.GetBlockEntity(point.X, point.Y, point.Z);
                if (blockEntity != null)
                {
                    ComponentInventoryBase inventoryBase = blockEntity.Entity.FindComponent<ComponentInventoryBase>();
                    if (copyData.DirectData != null)
                    {
                        var slots = (List<ComponentInventoryBase.Slot>)copyData.DirectData;
                        if (copyData.Id == 27)
                        {
                            for (int s = 0; s < slots.Count - 2; s++)
                            {
                                inventoryBase.AddSlotItems(s, slots[s].Value, slots[s].Count);
                            }
                        }
                        else
                        {
                            for (int s = 0; s < slots.Count; s++)
                            {
                                inventoryBase.AddSlotItems(s, slots[s].Value, slots[s].Count);
                            }
                        }
                    }
                }
            }
            else if (copyData.Id == 97 || copyData.Id == 210 || copyData.Id == 98 || copyData.Id == 211)
            {
                SubsystemCommandDef.m_subsystemTerrain.ChangeCell(point.X, point.Y, point.Z, copyData.Value);
                SubsystemSignBlockBehavior signBlockBehavior = SubsystemCommandDef.Project.FindSubsystem<SubsystemSignBlockBehavior>();
                if (copyData.DirectData != null)
                {
                    signBlockBehavior.SetSignData(point, ((SignData)copyData.DirectData).Lines, ((SignData)copyData.DirectData).Colors, ((SignData)copyData.DirectData).Url);
                }
            }
            else if (copyData.Id == CommandBlock.Index)
            {
                SubsystemCommandDef.m_subsystemTerrain.ChangeCell(point.X, point.Y, point.Z, copyData.Value);
                SubsystemCommandBlockBehavior commandBlockBehavior = SubsystemCommandDef.Project.FindSubsystem<SubsystemCommandBlockBehavior>();
                if (copyData.DirectData != null)
                {
                    commandBlockBehavior.SetCommandData(point, ((CommandData)copyData.DirectData).Line);
                }
            }
            else if (copyData.Id == 186)
            {
                SubsystemCommandDef.m_subsystemTerrain.ChangeCell(point.X, point.Y, point.Z, copyData.Value);
                SubsystemMemoryBankBlockBehavior bankBlockBehavior = SubsystemCommandDef.Project.FindSubsystem<SubsystemMemoryBankBlockBehavior>();
                if (copyData.DirectData != null)
                {
                    bankBlockBehavior.SetBlockData(point, (MemoryBankData)copyData.DirectData);
                }
            }
            else if (copyData.Id == 227 || copyData.Id == 94 || copyData.Id == 163 || copyData.Id == 164 || copyData.Id == 193 || copyData.Id == 202 || copyData.Id == 31)
            {
                SubsystemCommandDef.m_subsystemTerrain.ChangeCell(point.X, point.Y, point.Z, copyData.Value);
            }
            else if (applyChangeCell)
            {
                SubsystemCommandDef.m_subsystemTerrain.ChangeCell(point.X, point.Y, point.Z, copyData.Value);
            }
            else
            {
                SubsystemCommandDef.m_subsystemTerrain.Terrain.SetCellValueFast(point.X, point.Y, point.Z, copyData.Value);
            }
        }

        public void SetMirrorValue(CopyBlockData blockData, string plane)
        {
            Block block = BlocksManager.Blocks[blockData.Id];
            if (blockData.Id == 227 && blockData.DirectData != null)
            {
                FurnitureDesign design = ((FurnitureDesign)blockData.DirectData).Clone();
                int rotate = FurnitureBlock.GetRotation(blockData.Data);
                rotate = 4 - rotate;
                switch (plane)
                {
                    case "xoy": design.Rotate(1, rotate); design.Mirror(0); break;
                    case "xoz": design.Rotate(1, rotate); design.Mirror(1); design.Rotate(2, 2); break;
                    case "zoy": design.Rotate(1, rotate); design.Mirror(1); break;
                    default: break;
                }
                FurnitureDesign resultDesign = SubsystemCommandDef.m_subsystemFurnitureBlockBehavior.TryAddDesign(design);
                blockData.Value = Terrain.MakeBlockValue(227, 0, FurnitureBlock.SetDesignIndex(0, resultDesign.Index, resultDesign.ShadowStrengthFactor, resultDesign.IsLightEmitter));
            }
            else if (block is SlabBlock)
            {
                if (plane == "xoz")
                {
                    bool top = SlabBlock.GetIsTop(blockData.Data);
                    blockData.Value = Terrain.ReplaceData(blockData.Value, SlabBlock.SetIsTop(blockData.Data, !top));
                }
            }
            else if (block is StairsBlock)
            {
                StairsBlock.CornerType type = StairsBlock.GetCornerType(blockData.Data);
                bool top = StairsBlock.GetIsUpsideDown(blockData.Data);
                int rotate = StairsBlock.GetRotation(blockData.Data);
                if (plane == "xoz")
                {
                    blockData.Value = Terrain.ReplaceData(blockData.Value, StairsBlock.SetIsUpsideDown(blockData.Data, !top));
                }
                else if (plane == "xoy")
                {
                    if (type == StairsBlock.CornerType.None)
                    {
                        switch (rotate)
                        {
                            case 0: rotate = 2; break;
                            case 2: rotate = 0; break;
                        }
                    }
                    else
                    {
                        switch (rotate)
                        {
                            case 0: rotate = 3; break;
                            case 3: rotate = 0; break;
                            case 1: rotate = 2; break;
                            case 2: rotate = 1; break;
                        }
                    }
                    blockData.Value = Terrain.ReplaceData(blockData.Value, StairsBlock.SetRotation(blockData.Data, rotate));
                }
                else if (plane == "zoy")
                {
                    if (type == StairsBlock.CornerType.None)
                    {
                        switch (rotate)
                        {
                            case 1: rotate = 3; break;
                            case 3: rotate = 1; break;
                        }
                    }
                    else
                    {
                        switch (rotate)
                        {
                            case 0: rotate = 1; break;
                            case 1: rotate = 0; break;
                            case 2: rotate = 3; break;
                            case 3: rotate = 2; break;
                        }
                    }
                    blockData.Value = Terrain.ReplaceData(blockData.Value, StairsBlock.SetRotation(blockData.Data, rotate));
                }
            }
            else if (block is DoorBlock)
            {
                int rotate = DoorBlock.GetRotation(blockData.Data);
                if (plane == "xoy")
                {
                    if (rotate == 0) rotate = 2;
                    else if (rotate == 2) rotate = 0;
                }
                else if (plane == "zoy")
                {
                    if (rotate == 1) rotate = 3;
                    else if (rotate == 3) rotate = 1;
                }
                blockData.Value = Terrain.ReplaceData(blockData.Value, DoorBlock.SetRotation(blockData.Data, rotate));
            }
            else if (block is LadderBlock)
            {
                int rotate = LadderBlock.GetFace(blockData.Data);
                if (plane == "xoy")
                {
                    if (rotate == 0) rotate = 2;
                    else if (rotate == 2) rotate = 0;
                }
                else if (plane == "zoy")
                {
                    if (rotate == 1) rotate = 3;
                    else if (rotate == 3) rotate = 1;
                }
                blockData.Value = Terrain.ReplaceData(blockData.Value, LadderBlock.SetFace(blockData.Data, rotate));
            }
            else if (block is TrapdoorBlock)
            {
                if (plane == "xoy")
                {
                    int rotate = TrapdoorBlock.GetRotation(blockData.Data);
                    if (rotate == 0) rotate = 2;
                    else if (rotate == 2) rotate = 0;
                    blockData.Value = Terrain.ReplaceData(blockData.Value, TrapdoorBlock.SetRotation(blockData.Data, rotate));
                }
                else if (plane == "zoy")
                {
                    int rotate = TrapdoorBlock.GetRotation(blockData.Data);
                    if (rotate == 1) rotate = 3;
                    else if (rotate == 3) rotate = 1;
                    blockData.Value = Terrain.ReplaceData(blockData.Value, TrapdoorBlock.SetRotation(blockData.Data, rotate));
                }
                else if (plane == "xoz")
                {
                    bool top = TrapdoorBlock.GetUpsideDown(blockData.Data);
                    blockData.Value = Terrain.ReplaceData(blockData.Value, TrapdoorBlock.SetUpsideDown(blockData.Data, !top));
                }
            }
            else if (block is AttachedSignBlock)
            {
                int rotate = AttachedSignBlock.GetFace(blockData.Data);
                if (plane == "xoy")
                {
                    if (rotate == 0) rotate = 2;
                    else if (rotate == 2) rotate = 0;
                }
                else if (plane == "zoy")
                {
                    if (rotate == 1) rotate = 3;
                    else if (rotate == 3) rotate = 1;
                }
                blockData.Value = Terrain.ReplaceData(blockData.Value, AttachedSignBlock.SetFace(blockData.Data, rotate));
            }
            else if (block is PostedSignBlock)
            {
                int rotate = PostedSignBlock.GetDirection(blockData.Data);
                if (plane == "xoz")
                {
                    bool top = PostedSignBlock.GetHanging(blockData.Data);
                    blockData.Value = Terrain.ReplaceData(blockData.Value, PostedSignBlock.SetHanging(blockData.Data, !top));
                }
                else if (plane == "xoy")
                {
                    switch (rotate)
                    {
                        case 0: rotate = 4; break;
                        case 4: rotate = 0; break;
                        case 1: rotate = 3; break;
                        case 3: rotate = 1; break;
                        case 5: rotate = 7; break;
                        case 7: rotate = 5; break;
                    }
                    blockData.Value = Terrain.ReplaceData(blockData.Value, PostedSignBlock.SetDirection(blockData.Data, rotate));
                }
                else if (plane == "zoy")
                {
                    switch (rotate)
                    {
                        case 1: rotate = 7; break;
                        case 7: rotate = 1; break;
                        case 2: rotate = 6; break;
                        case 6: rotate = 2; break;
                        case 3: rotate = 5; break;
                        case 5: rotate = 3; break;
                    }
                    blockData.Value = Terrain.ReplaceData(blockData.Value, PostedSignBlock.SetDirection(blockData.Data, rotate));
                }
            }
            else if (block is FenceGateBlock)
            {
                int rotate = FenceGateBlock.GetRotation(blockData.Data);
                if (plane == "xoy")
                {
                    if (rotate == 0) rotate = 2;
                    else if (rotate == 2) rotate = 0;
                }
                else if (plane == "zoy")
                {
                    if (rotate == 1) rotate = 3;
                    else if (rotate == 3) rotate = 1;
                }
                blockData.Value = Terrain.ReplaceData(blockData.Value, FenceGateBlock.SetRotation(blockData.Data, rotate));
            }
            else if (block is DispenserBlock)
            {
                int rotate = DispenserBlock.GetDirection(blockData.Data);
                if (plane == "xoy")
                {
                    if (rotate == 0) rotate = 2;
                    else if (rotate == 2) rotate = 0;
                }
                else if (plane == "zoy")
                {
                    if (rotate == 1) rotate = 3;
                    else if (rotate == 3) rotate = 1;
                }
                else if (plane == "xoz")
                {
                    if (rotate == 4) rotate = 5;
                    else if (rotate == 5) rotate = 4;
                }
                blockData.Value = Terrain.ReplaceData(blockData.Value, DispenserBlock.SetDirection(blockData.Data, rotate));
            }
            else if (block is TorchBlock)
            {
                int rotate = blockData.Data;
                if (plane == "xoy")
                {
                    if (rotate == 0) rotate = 2;
                    else if (rotate == 2) rotate = 0;
                }
                else if (plane == "zoy")
                {
                    if (rotate == 1) rotate = 3;
                    else if (rotate == 3) rotate = 1;
                }
                blockData.Value = Terrain.ReplaceData(blockData.Value, rotate);
            }
        }

        public void SetRotateValue(CopyBlockData blockData, string axis, string angle)
        {
            Block block = BlocksManager.Blocks[blockData.Id];
            int angleIndex = 0;
            switch (angle)
            {
                case "+90": angleIndex = 1; break;
                case "+180": angleIndex = 2; break;
                case "+270": angleIndex = 3; break;
                default: break;
            }
            if (blockData.Id == 227 && blockData.DirectData != null)
            {
                FurnitureDesign design = ((FurnitureDesign)blockData.DirectData).Clone();
                int rotate = FurnitureBlock.GetRotation(blockData.Data);
                if (axis == "+x")
                {
                    switch (angle)
                    {
                        case "+90": design.Rotate(0, 3); design.Rotate(2, rotate); break;
                        case "+180": design.Rotate(0, 2); design.Rotate(1, rotate); break;
                        case "+270": design.Rotate(0, 1); design.Rotate(2, 4 - rotate); break;
                        default: break;
                    }
                    FurnitureDesign resultDesign = SubsystemCommandDef.m_subsystemFurnitureBlockBehavior.TryAddDesign(design);
                    blockData.Value = Terrain.MakeBlockValue(227, 0, FurnitureBlock.SetDesignIndex(0, resultDesign.Index, resultDesign.ShadowStrengthFactor, resultDesign.IsLightEmitter));
                }
                else if (axis == "+y")
                {
                    rotate = (rotate + 4 - angleIndex) % 4;
                    blockData.Value = Terrain.ReplaceData(blockData.Value, FurnitureBlock.SetRotation(blockData.Data, rotate));
                }
                else if (axis == "+z")
                {
                    switch (angle)
                    {
                        case "+90": design.Rotate(2, 1); design.Rotate(0, rotate); break;
                        case "+180": design.Rotate(2, 2); design.Rotate(1, rotate); break;
                        case "+270": design.Rotate(2, 3); design.Rotate(0, 4 - rotate); break;
                        default: break;
                    }
                    FurnitureDesign resultDesign = SubsystemCommandDef.m_subsystemFurnitureBlockBehavior.TryAddDesign(design);
                    blockData.Value = Terrain.MakeBlockValue(227, 0, FurnitureBlock.SetDesignIndex(0, resultDesign.Index, resultDesign.ShadowStrengthFactor, resultDesign.IsLightEmitter));
                }
            }
            else if (block is StairsBlock)
            {
                StairsBlock.CornerType type = StairsBlock.GetCornerType(blockData.Data);
                int rotate = StairsBlock.GetRotation(blockData.Data);
                if (axis == "+y")
                {
                    rotate = (rotate + 4 - angleIndex) % 4;
                    blockData.Value = Terrain.ReplaceData(blockData.Value, StairsBlock.SetRotation(blockData.Data, rotate));
                }
                else if (axis == "+x")
                {
                    if (type == StairsBlock.CornerType.None)
                    {
                        int data = GetIrregularData(new int[4] { 0, 4, 6, 2 }, blockData.Data, angleIndex);
                        if (data != -1)
                        {
                            blockData.Value = Terrain.ReplaceData(blockData.Value, data);
                        }
                    }
                }
                else if (axis == "+z")
                {
                    if (type == StairsBlock.CornerType.None)
                    {
                        int data = GetIrregularData(new int[4] { 1, 3, 7, 5 }, blockData.Data, angleIndex);
                        if (data != -1)
                        {
                            blockData.Value = Terrain.ReplaceData(blockData.Value, data);
                        }
                    }
                }
            }
            else if (block is WoodBlock)
            {
                if (axis == "+y")
                {
                    if (angleIndex % 2 != 0 && blockData.Data != 0)
                    {
                        int data = blockData.Data;
                        if (data == 1) data = 2;
                        else if (data == 2) data = 1;
                        blockData.Value = Terrain.ReplaceData(blockData.Value, data);
                    }
                }
                else if (axis == "+x")
                {
                    if (angleIndex % 2 != 0 && blockData.Data != 2)
                    {
                        int data = blockData.Data;
                        if (data == 0) data = 1;
                        else if (data == 1) data = 0;
                        blockData.Value = Terrain.ReplaceData(blockData.Value, data);
                    }
                }
                else if (axis == "+z")
                {
                    if (angleIndex % 2 != 0 && blockData.Data != 1)
                    {
                        int data = blockData.Data;
                        if (data == 0) data = 2;
                        else if (data == 2) data = 0;
                        blockData.Value = Terrain.ReplaceData(blockData.Value, data);
                    }
                }
            }
            else if (block is DoorBlock)
            {
                if (axis == "+y")
                {
                    int rotate = DoorBlock.GetRotation(blockData.Data);
                    rotate = (rotate + 4 - angleIndex) % 4;
                    blockData.Value = Terrain.ReplaceData(blockData.Value, DoorBlock.SetRotation(blockData.Data, rotate));
                }
            }
            else if (block is LadderBlock)
            {
                if (axis == "+y")
                {
                    int rotate = LadderBlock.GetFace(blockData.Data);
                    rotate = (rotate + 4 - angleIndex) % 4;
                    blockData.Value = Terrain.ReplaceData(blockData.Value, LadderBlock.SetFace(blockData.Data, rotate));
                }
            }
            else if (block is TrapdoorBlock)
            {
                if (axis == "+y")
                {
                    int rotate = TrapdoorBlock.GetRotation(blockData.Data);
                    rotate = (rotate + 4 - angleIndex) % 4;
                    blockData.Value = Terrain.ReplaceData(blockData.Value, TrapdoorBlock.SetRotation(blockData.Data, rotate));
                }
            }
            else if (block is AttachedSignBlock)
            {
                if (axis == "+y")
                {
                    int rotate = AttachedSignBlock.GetFace(blockData.Data);
                    rotate = (rotate + 4 - angleIndex) % 4;
                    blockData.Value = Terrain.ReplaceData(blockData.Value, AttachedSignBlock.SetFace(blockData.Data, rotate));
                }
            }
            else if (block is PostedSignBlock)
            {
                if (axis == "+y")
                {
                    int rotate = PostedSignBlock.GetDirection(blockData.Data);
                    rotate = (rotate + 8 - 2 * angleIndex) % 8;
                    blockData.Value = Terrain.ReplaceData(blockData.Value, PostedSignBlock.SetDirection(blockData.Data, rotate));
                }
            }
            else if (block is FenceGateBlock)
            {
                if (axis == "+y")
                {
                    int rotate = FenceGateBlock.GetRotation(blockData.Data);
                    rotate = (rotate + 4 - angleIndex) % 4;
                    blockData.Value = Terrain.ReplaceData(blockData.Value, FenceGateBlock.SetRotation(blockData.Data, rotate));
                }
            }
            else if (block is DispenserBlock)
            {
                int rotate = DispenserBlock.GetDirection(blockData.Data);
                if (axis == "+y")
                {
                    if (rotate >= 0 && rotate < 4) rotate = (rotate + 4 - angleIndex) % 4;
                }
                else if (axis == "+x")
                {
                    int newRotate = GetIrregularData(new int[4] { 0, 5, 2, 4 }, rotate, angleIndex);
                    if (newRotate != -1) rotate = newRotate;
                }
                else if (axis == "+z")
                {
                    int newRotate = GetIrregularData(new int[4] { 1, 4, 3, 5 }, rotate, angleIndex);
                    if (newRotate != -1) rotate = newRotate;
                }
                blockData.Value = Terrain.ReplaceData(blockData.Value, DispenserBlock.SetDirection(blockData.Data, rotate));
            }
            else if (block is TorchBlock)
            {
                if (axis == "+y")
                {
                    int rotate = blockData.Data;
                    if (rotate >= 0 && rotate < 4)
                    {
                        rotate = (rotate + 4 - angleIndex) % 4;
                    }
                    blockData.Value = Terrain.ReplaceData(blockData.Value, rotate);
                }
            }
        }

        public int GetIrregularData(int[] adata, int data, int angleIndex)
        {
            for (int a = 0; a < adata.Length; a++)
            {
                if (data == adata[a])
                {
                    return adata[(a + angleIndex) % adata.Length];
                }
            }
            return -1;
        }

        public Point3 GetMirrorPoint(Point3 p, Point3 planePoint, string plane, bool laminate)
        {
            Point3 point = Point3.Zero;
            switch (plane)
            {
                case "xoy": point = new Point3(p.X, p.Y, 2 * planePoint.Z - p.Z); break;
                case "xoz": point = new Point3(p.X, 2 * planePoint.Y - p.Y, p.Z); break;
                case "zoy": point = new Point3(2 * planePoint.X - p.X, p.Y, p.Z); break;
                default: break;
            }
            if (laminate)
            {
                switch (plane)
                {
                    case "xoy": point.Z = ((point.Z - planePoint.Z) == 0) ? point.Z : ((point.Z - planePoint.Z > 0) ? point.Z - 1 : point.Z + 1); break;
                    case "xoz": point.Y = ((point.Y - planePoint.Y) == 0) ? point.Y : ((point.Y - planePoint.Y > 0) ? point.Y - 1 : point.Y + 1); break;
                    case "zoy": point.X = ((point.X - planePoint.X) == 0) ? point.X : ((point.X - planePoint.X > 0) ? point.X - 1 : point.X + 1); break;
                    default: break;
                }
            }
            return point;
        }

        public Point3 GetRotatePoint(Point3 p, Point3 axisPoint, string axis, string angle)
        {
            Point3 point = Point3.Zero;
            if (axis == "+x")
            {
                switch (angle)
                {
                    case "+90": point = new Point3(p.X, axisPoint.Y - p.Z + axisPoint.Z, axisPoint.Z + p.Y - axisPoint.Y); break;
                    case "+180": point = new Point3(p.X, 2 * axisPoint.Y - p.Y, 2 * axisPoint.Z - p.Z); break;
                    case "+270": point = new Point3(p.X, axisPoint.Y + p.Z - axisPoint.Z, axisPoint.Z - p.Y + axisPoint.Y); break;
                    default: break;
                }
            }
            else if (axis == "+y")
            {
                switch (angle)
                {
                    case "+90": point = new Point3(axisPoint.X - p.Z + axisPoint.Z, p.Y, axisPoint.Z + p.X - axisPoint.X); break;
                    case "+180": point = new Point3(2 * axisPoint.X - p.X, p.Y, 2 * axisPoint.Z - p.Z); break;
                    case "+270": point = new Point3(axisPoint.X + p.Z - axisPoint.Z, p.Y, axisPoint.Z - p.X + axisPoint.X); break;
                    default: break;
                }
            }
            else if (axis == "+z")
            {
                switch (angle)
                {
                    case "+90": point = new Point3(axisPoint.X - p.Y + axisPoint.Y, axisPoint.Y + p.X - axisPoint.X, p.Z); break;
                    case "+180": point = new Point3(2 * axisPoint.X - p.X, 2 * axisPoint.Y - p.Y, p.Z); break;
                    case "+270": point = new Point3(axisPoint.X + p.Y - axisPoint.Y, axisPoint.Y - p.X + axisPoint.X, p.Z); break;
                    default: break;
                }
            }
            return point;
        }

        public void GetCopyExtraData(CopyBlockData copyData, Point3 point)
        {
            if (copyData.Id == 27 || copyData.Id == 45 || copyData.Id == 64 || copyData.Id == 216)
            {
                ComponentBlockEntity blockEntity = SubsystemCommandDef.m_subsystemBlockEntities.GetBlockEntity(point.X, point.Y, point.Z);
                if (blockEntity != null)
                {
                    List<ComponentInventoryBase.Slot> inventoryBase = new List<ComponentInventoryBase.Slot>();
                    switch (copyData.Id)
                    {
                        case 27:
                            {
                                var componentblockEntity = blockEntity.Entity.FindComponent<ComponentCraftingTable>();
                                if (componentblockEntity != null)
                                {
                                    foreach (var s in componentblockEntity.m_slots)
                                    {
                                        ComponentInventoryBase.Slot slot = new ComponentInventoryBase.Slot();
                                        slot.Count = s.Count;
                                        slot.Value = s.Value;
                                        inventoryBase.Add(slot);
                                    }
                                }
                                break;
                            }
                        case 45:
                            {
                                var componentblockEntity = blockEntity.Entity.FindComponent<ComponentChest>();
                                if (componentblockEntity != null)
                                {
                                    foreach (var s in componentblockEntity.m_slots)
                                    {
                                        ComponentInventoryBase.Slot slot = new ComponentInventoryBase.Slot();
                                        slot.Count = s.Count;
                                        slot.Value = s.Value;
                                        inventoryBase.Add(slot);
                                    }
                                }
                                break;
                            }
                        case 64:
                            {
                                var componentblockEntity = blockEntity.Entity.FindComponent<ComponentFurnace>();
                                if (componentblockEntity != null)
                                {
                                    foreach (var s in componentblockEntity.m_slots)
                                    {
                                        ComponentInventoryBase.Slot slot = new ComponentInventoryBase.Slot();
                                        slot.Count = s.Count;
                                        slot.Value = s.Value;
                                        inventoryBase.Add(slot);
                                    }
                                }
                                break;
                            }
                        case 216:
                            {
                                var componentblockEntity = blockEntity.Entity.FindComponent<ComponentDispenser>();
                                if (componentblockEntity != null)
                                {
                                    foreach (var s in componentblockEntity.m_slots)
                                    {
                                        ComponentInventoryBase.Slot slot = new ComponentInventoryBase.Slot();
                                        slot.Count = s.Count;
                                        slot.Value = s.Value;
                                        inventoryBase.Add(slot);
                                    }
                                }
                                break;
                            }
                        default: break;
                    }
                    copyData.DirectData = inventoryBase;
                    if (HandleExtraData)
                    {
                        copyData.ExtraData = string.Empty;
                        foreach (var ib in inventoryBase)
                        {
                            copyData.ExtraData += (ib.Value + ":" + ib.Count) + ";";
                        }
                    }
                }
            }
            else if (copyData.Id == 97 || copyData.Id == 210 || copyData.Id == 98 || copyData.Id == 211)
            {
                SubsystemSignBlockBehavior signBlockBehavior = SubsystemCommandDef.Project.FindSubsystem<SubsystemSignBlockBehavior>();
                SignData signData = signBlockBehavior.GetSignData(point);
                if (signData != null)
                {
                    SignData newSignData = new SignData();
                    newSignData.Colors = new Color[signData.Colors.Length];
                    newSignData.Lines = new string[signData.Colors.Length];
                    newSignData.Url = signData.Url;
                    copyData.DirectData = newSignData;
                    copyData.ExtraData = string.Empty;
                    copyData.ExtraData += "Colors=";
                    for (int sc = 0; sc < signData.Colors.Length; sc++)
                    {
                        newSignData.Colors[sc] = signData.Colors[sc];
                        copyData.ExtraData += signData.Colors[sc].ToString() + ";";
                    }
                    copyData.ExtraData += "&Lines=";
                    for (int sc = 0; sc < signData.Lines.Length; sc++)
                    {
                        newSignData.Lines[sc] = signData.Lines[sc];
                        copyData.ExtraData += signData.Lines[sc] + ";";
                    }
                    copyData.ExtraData += "&Url=" + signData.Url;
                }
            }
            else if (copyData.Id == CommandBlock.Index)
            {
                SubsystemCommandBlockBehavior commandBlockBehavior = SubsystemCommandDef.Project.FindSubsystem<SubsystemCommandBlockBehavior>();
                CommandData commandData = commandBlockBehavior.GetCommandData(point);
                if (commandData != null)
                {
                    CommandData newCommandData = new CommandData(point, commandData.Line);
                    newCommandData.TrySetValue();
                    copyData.DirectData = newCommandData;
                    copyData.ExtraData = commandData.Line;
                }
            }
            else if (copyData.Id == 186)
            {
                SubsystemMemoryBankBlockBehavior bankBlockBehavior = SubsystemCommandDef.Project.FindSubsystem<SubsystemMemoryBankBlockBehavior>();
                MemoryBankData memoryBankData = bankBlockBehavior.GetBlockData(point);
                if (memoryBankData != null)
                {
                    MemoryBankData newMemoryBankData = (MemoryBankData)memoryBankData.Copy();
                    copyData.DirectData = newMemoryBankData;
                    if (HandleExtraData)
                    {
                        copyData.ExtraData = newMemoryBankData.SaveString();
                    }
                }
            }
            else if (copyData.Id == 227)
            {
                int fid = FurnitureBlock.GetDesignIndex(copyData.Data);
                FurnitureDesign design = SubsystemCommandDef.Project.FindSubsystem<SubsystemFurnitureBlockBehavior>().GetDesign(fid);
                copyData.DirectData = design.Clone();
                if (HandleExtraData)
                {
                    //copyData.ExtraData = design.ToString();
                }
            }
        }

        public List<FurnitureDesign> SortFurniture()
        {
            List<FurnitureDesign> allFurnitures = new List<FurnitureDesign>();
            List<FurnitureDesign> sortFurnitures = new List<FurnitureDesign>();
            foreach (var copydata in CopyBlockDatas.Keys)
            {
                if (CopyBlockDatas[copydata].Id == 227)
                {
                    if (CopyBlockDatas[copydata].DirectData != null)
                    {
                        allFurnitures.Add((FurnitureDesign)CopyBlockDatas[copydata].DirectData);
                    }
                }
            }
            int k = 1;
            foreach (FurnitureDesign furniture in allFurnitures)
            {
                bool exist = false;
                foreach (FurnitureDesign furniture2 in sortFurnitures)
                {
                    if (furniture.Compare(furniture2))
                    {
                        furniture.Index = furniture2.Index;
                        exist = true;
                        break;
                    }
                }
                if (!exist)
                {
                    furniture.Index = k;
                    sortFurnitures.Add(furniture);
                    k++;
                }
            }
            return sortFurnitures;
        }
    }
}